# Column.java

    package org.codefilarete.stalactite.sql.ddl.structure;

    import org.codefilarete.stalactite.query.api.JoinLink;
    import org.codefilarete.stalactite.query.api.Selectable;
    import org.codefilarete.stalactite.sql.ddl.DDLAppender;
    import org.codefilarete.stalactite.sql.ddl.Size;

    import javax.annotation.Nullable;

    /**
     * Column of a table.
     *
     * @param <O> the Java type this columns is mapped to
     * @author Guillaume Mary
     */
    public class Column<T extends Table, O> implements Selectable<O>, JoinLink<T, O> {

    	private final T table;
    	private final String name;
    	private final Class<O> javaType;
    	@Nullable
    	private Size size;
    	@Nullable
    	private Boolean nullable;
    	private final String absoluteName;
    	private final String alias;
    	private boolean primaryKey;
    	private boolean autoGenerated;

    	/**
    	 * Build a column
    	 */
    	public Column(T owner, String name, Class<O> javaType) {
    		this(owner, name, javaType, null);
    	}

    	/**
    	 * Build a column with a size
    	 */
    	public Column(T owner, String name, Class<O> javaType, @Nullable Size size) {
    		this.table = owner;
    		this.name = name;
    		this.javaType = javaType;
    		this.size = size;
    		this.absoluteName = getTable().getName() + "." + getName();
    		this.alias = getTable().getName() + "_" + getName();
    		this.nullable = null;
    	}

    	public Column(T owner, String name, Class<O> javaType, @Nullable Size size, @Nullable Boolean nullable) {
    		this.table = owner;
    		this.name = name;
    		this.javaType = javaType;
    		this.size = size;
    		this.absoluteName = getTable().getName() + "." + getName();
    		this.alias = getTable().getName() + "_" + getName();
    		this.nullable = nullable;
    	}

    	@Override
    	public T getOwner() {
    		return getTable();
    	}

    	@Override
    	public String getExpression() {
    		return this.name;
    	}

    	@Override
    	public Class<O> getJavaType() {
    		return this.javaType;
    	}

    	public T getTable() {
    		return table;
    	}

    	public String getName() {
    		return name;
    	}

    	/**
    	 * Gives the column name prefixed by table name. Allows column identification in a schema.
    	 *
    	 * @return getTable().getName() + "." + getName()
    	 */
    	public String getAbsoluteName() {
    		return absoluteName;
    	}

    	/**
    	 * Provides a default alias usable for select clause
    	 * @return getTable().getName() +"_" + getName()
    	 */
    	public String getAlias() {
    		return alias;
    	}

    	@Nullable
    	public Size getSize() {
    		return size;
    	}

    	public void setSize(@Nullable Size size) {
    		this.size = size;
    	}

    	/**
    	 *
    	 * @return null if the property wasn't set, certainly meaning that the column is left nullable
    	 * @see org.codefilarete.stalactite.sql.ddl.DDLTableGenerator#generateCreateColumn(Column, DDLAppender)
    	 */
    	@Nullable
    	public Boolean isNullable() {
    		return nullable;
    	}

    	public void setNullable(Boolean nullable) {
    		this.nullable = nullable;
    	}

    	/**
    	 * Fluent API
    	 * @param nullable is this Column is optional or mandatory
    	 * @return this
    	 */
    	public Column<T, O> nullable(boolean nullable) {
    		setNullable(nullable);
    		return this;
    	}

    	/**
    	 * Fluent API. Set this column as not nullable.
    	 * @return this
    	 */
    	public Column<T, O> notNull() {
    		return nullable(false);
    	}

    	public boolean isPrimaryKey() {
    		return primaryKey;
    	}

    	public void setPrimaryKey(boolean primaryKey) {
    		this.primaryKey = primaryKey;
    	}

    	/**
    	 * Set this column as primary of the table, or participate to it if there are several ones
    	 *
    	 * @return this
    	 */
    	public Column<T, O> primaryKey() {
    		setPrimaryKey(true);
    		return this;
    	}

    	public boolean isAutoGenerated() {
    		return autoGenerated;
    	}

    	public void setAutoGenerated(boolean autoGenerated) {
    		if (!isPrimaryKey() && autoGenerated) {
    			throw new UnsupportedOperationException("Auto generate operation is only supported for primary key, please declare the column as primary key before");
    		}
    		this.autoGenerated = autoGenerated;
    	}

    	public Column<T, O> autoGenerated() {
    		setAutoGenerated(true);
    		return this;
    	}

    	/* Do not implement equals/hashCode, which can be tempting (based on absolute name for instance)
    	 * because it breaks possibility to add clones of column (through clones of table) in select clause when
    	 * joining several times same table is necessary : for that case column clones must be considered distinct
    	 */

    	/**
    	 * Overridden only for simple print (debug)
    	 */
    	@Override
    	public String toString() {
    		return getAbsoluteName();
    	}
    }